package GUI;

import Operatori.Sqrt;
import Operatori.Log;
import Functii.ParantezaStanga;
import Functii.ParantezaDreapta;
import Operatori.*;
import FunctiiTrigo.*;
import FunctiiElementare.*;
import Arbori.*;

public class Parsare implements Command {

	private int i = 0;
	private Nod k = null;
	private String sir;
	public String err;

	public ArboreFunctional a = null;

	public Parsare(ArboreFunctional a, String f) {
		this.a = a;
		this.sir = f;
		this.err = "";
	}

	public void setI(int p) {
		this.i = p;
	}

	public int getI() {
		return i;
	}

	public Nod identificare(String sir) {
		Nod op = null;
		if (i < sir.length()) {

			switch (sir.charAt(i)) {
			case '(':
				op = new ParantezaStanga();
				break;
			case ')':
				op = new ParantezaDreapta();
				break;
			case 'x':
				op = new Necunoscuta();
				break;
			case '+':
				op = new Plus();
				break;
			case '-':
				op = new Minus();
				break;
			case '*':
				op = new Produs();
				break;
			case '/':
				op = new Cat();
				break;
			case '^':
				op = new Putere();
				break;
			case 's':
				if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'i'
						&& (i + 2 < sir.length()) && sir.charAt(i + 2) == 'n') {
					op = new Sin();
					i = i + 2;
				} else {
					if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'q'
							&& (i + 2 < sir.length())
							&& sir.charAt(i + 2) == 'r'
							&& (i + 3 < sir.length())
							&& sir.charAt(i + 3) == 't') {
						op = new Sqrt();
						i = i + 3;
					}
				}
				break;
			case 'c':
				if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'o'
						&& (i + 2 < sir.length()) && sir.charAt(i + 2) == 's') {
					op = new Cos();
					i = i + 2;
				} else {
					if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 't'
							&& (i + 2 < sir.length())
							&& sir.charAt(i + 2) == 'g') {
						op = new Ctg();
						i = i + 2;
					}
				}
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				double nr = 0;
				while (i < sir.length()
						&& (sir.charAt(i) == '1' || sir.charAt(i) == '2'
								|| sir.charAt(i) == '3' || sir.charAt(i) == '4'
								|| sir.charAt(i) == '5' || sir.charAt(i) == '6'
								|| sir.charAt(i) == '7' || sir.charAt(i) == '8'
								|| sir.charAt(i) == '9' || sir.charAt(i) == '0')) {
					nr = nr * 10 + sir.charAt(i) - '0';
					i++;
				}
				if (i < sir.length() && sir.charAt(i) == '.') {
					int j = 0;
					i++;
					while ((sir.charAt(i) == '1' || sir.charAt(i) == '2'
							|| sir.charAt(i) == '3' || sir.charAt(i) == '4'
							|| sir.charAt(i) == '5' || sir.charAt(i) == '6'
							|| sir.charAt(i) == '7' || sir.charAt(i) == '8'
							|| sir.charAt(i) == '9' || sir.charAt(i) == '0')
							&& i < sir.length()) {
						nr = nr * 10 + sir.charAt(i) - '0';
						i++;
						j++;
					}
					i--;
					nr = nr / Math.pow((double) 10, (double) j);
				}
				i--;
				op = new Constanta(nr);
				break;
			case 'p':
				if (sir.charAt(i) == 'i') {
					i++;
					op = new Constanta(3.14);
				} else {
					if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'o'
							&& (i + 2 < sir.length())
							&& sir.charAt(i + 2) == 'w') {
						op = new Putere();
						i = i + 2;
					}
				}
				break;
			case 'l':
				if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'o'
						&& (i + 2 < sir.length()) && sir.charAt(i + 2) == 'g') {
					op = new Log();
					i = i + 2;
				} else {
					if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'n') {
						op = new Ln();
						i++;
					}
				}
				break;
			case 't':
				if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'g') {
					op = new Tg();
					i++;
				}
				break;
			case 'e':
				if ((i + 1 < sir.length()) && sir.charAt(i + 1) == 'x'
						&& (i + 2 < sir.length()) && sir.charAt(i + 2) == 'p') {
					op = new Exp();
					i = i + 2;
				}

			}
			i++;
		}

		return op;
	}

	public Nod expression(String sir) {
		if (i == sir.length()) {
			return k;
		} else {
			Nod n = identificare(sir);
			if (n != null && n.toString().contains("Constanta")) {
				Nod n1 = identificare(sir);
				if (n1 != null && n1.toString().contains("Operatori")) {
					Nod n2 = identificare(sir);
					if (n2 != null && n2.toString().contains("Necunoscuta")) {
						n1.setFStang(n);
						n1.setFDrept(n2);
						k = n1;
						return n1;
					} else {
						this.err = "Eroare. Asteptam un x!";
						return null;
					}
				} else {
					k = n;
					i--;
					return n;
				}
			} else if (n.toString().contains("Necunoscuta")) {
				Nod n1 = identificare(sir);
				if (n1 != null && n1.toString().contains("Operatori")) {
					Nod n2 = identificare(sir);
					if (n2 != null && n2.toString().contains("Constanta")) {
						n1.setFStang(n);
						n1.setFDrept(n2);
						k = n1;
						return n1;
					} else {
						err = "Eroare. Asteptam o constanta!";
						return null;
					}
				} else {
					k = n;
					i--;
					return n;
				}
			} else 
			if (n != null
					&& (n.toString().contains("Ln")
							|| n.toString().contains("Exp")
							|| n.toString().contains("Cos")
							|| n.toString().contains("Sin")
							|| n.toString().contains("Tg") || n.toString()
							.contains("Ctg"))) {
				Nod n1 = identificare(sir);
				if (n1 != null && n1.toString().contains("ParantezaStanga")) {
					n.setFStang(expression(sir));
					Nod n2 = identificare(sir);
					if (n2 != null
							&& n2.toString().contains("ParantezaDreapta")) {
						n1 = identificare(sir);
						if (n1 != null && n1.toString().contains("Operatori")) {
							n1.setFStang(n);
							n1.setFDrept(expression(sir));
							k = n1;
							return n1;
						} else {
							return k;
						}

					} else {
						err = "Eroare. Asteptam o ')'!";
						return null;
					}
				} else {
					err = "Eroare. Asteptam o '('!";
					return null;
				}

			} else if (n != null && n.toString().contains("ParantezaStanga")) {
				Nod n1 = identificare(sir);
				if (n1 != null
						&& (n1.toString().contains("Ln")
								|| n1.toString().contains("Exp")
								|| n1.toString().contains("Cos")
								|| n1.toString().contains("Sin")
								|| n1.toString().contains("Tg") || n1
								.toString().contains("Ctg"))) {
					Nod n2 = identificare(sir);
					if (n2 != null && n2.toString().contains("ParantezaStanga")) {
						n1.setFStang(expression(sir));
						Nod n3 = identificare(sir);
						if (n3 != null
								&& n3.toString().contains("ParantezaDreapta")) {
							// k = n1;
							n2 = identificare(sir);
							if (n2 != null
									&& n2.toString().contains(
											"ParantezaDreapta")) {
								n3 = identificare(sir);

								if (n3 != null
										&& n3.toString().contains("Operatori")) {

									n3.setFStang(n1);
									n3.setFDrept(expression(sir));
									k = n3;
									return n3;
								} else {
									return k;
								}
							} else {
								err = "Eroare. Asteptam o ')'!";
								return null;
							}
						} else {
							err = "Eroare. Asteptam o ')'!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o '('!";
						return null;
					}
				} else {
					if (n1 != null && n1.toString().contains("Log")
							|| n1.toString().contains("Pow")
							|| n1.toString().contains("Sqrt")) {
						Nod n2 = identificare(sir);
						if (n2 != null && n2.toString().contains("Constanta")) {
							Nod n3 = identificare(sir);
							if (n3 != null
									&& n3.toString()
											.contains("ParantezaStanga")) {
								n1.setFDrept(expression(sir));
								n3 = identificare(sir);
								if (n3 != null
										&& n3.toString().contains(
												"ParantezaDreapta")) {
									n1.setFStang(n2);
									n2 = identificare(sir);
									if (n2 != null
											&& n2.toString().contains(
													"ParantezaDreapta")) {
										n3 = identificare(sir);
										if (n3 != null
												&& n3.toString().contains(
														"Operatori")) {
											n3.setFStang(n1);
											n3.setFDrept(expression(sir));
											k = n3;
											return n3;
										} else {
											return k;
										}
									} else {
										err = "Eroare. Asteptam o ')'!";
										return null;
									}
								} else {
									err = "Eroare. Asteptam o ')'!";
									return null;
								}
							} else {
								err = "Eroare. Asteptam o '('!";
								return null;
							}
						} else {
							err = "Eroare. Asteptam o constanta!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o functie cunoscuta!";
						return null;
					}
				}
			} else if (n != null
					&& (n.toString().contains("Ln")
							|| n.toString().contains("Exp")
							|| n.toString().contains("Cos")
							|| n.toString().contains("Sin")
							|| n.toString().contains("Tg") || n.toString()
							.contains("Ctg"))) {
				Nod n1 = identificare(sir);
				if (n1 != null && n1.toString().contains("ParantezaStanga")) {
					n.setFStang(expression(sir));
					Nod n2 = identificare(sir);
					if (n2 != null
							&& n2.toString().contains("ParantezaDreapta")) {
						n1 = identificare(sir);
						if (n1 != null && n1.toString().contains("Operatori")) {
							n1.setFStang(n);
							n2 = identificare(sir);
							if (n2 != null
									&& n2.toString()
											.contains("ParantezaStanga")) {
								n1.setFDrept(expression(sir));
								Nod n3 = identificare(sir);
								if (n3.toString().contains("ParantezaDreapta")) {
									k = n1;
									return n1;
								} else {
									err = "Eroare. Asteptam o ')'!";
									return null;
								}
							} else {
								err = "Eroare. Asteptam o '('!";
								return null;
							}
						} else {
							err = "Eroare. Asteptam un operator!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o ')'!";
						return null;
					}
				} else {
					err = "Eroare. Asteptam o '('!";
					return null;
				}

			} else if (n != null && n.toString().contains("ParantezaStanga")) {
				Nod n1 = identificare(sir);
				if (n1 != null
						&& (n1.toString().contains("Ln")
								|| n1.toString().contains("Exp")
								|| n1.toString().contains("Cos")
								|| n1.toString().contains("Sin")
								|| n1.toString().contains("Tg") || n1
								.toString().contains("Ctg"))) {
					Nod n2 = identificare(sir);
					if (n2 != null && n2.toString().contains("ParantezaStanga")) {
						n1.setFStang(expression(sir));
						Nod n3 = identificare(sir);
						if (n3 != null
								&& n3.toString().contains("ParantezaDreapta")) {
							n2 = identificare(sir);
							if (n2 != null
									&& n2.toString().contains(
											"ParantezaDreapta")) {
								n3 = identificare(sir);
								if (n3 != null
										&& (n3.toString().contains("Produs")
												|| n3.toString()
														.contains("Cat") || n3
												.toString().contains("Minus"))) {
									n3.setFStang(n1);
									n2 = identificare(sir);
									if (n2 != null
											&& n2.toString().contains(
													"ParantezaStanga")) {
										n3.setFDrept(expression(sir));
										n2 = identificare(sir);
										if (n2 != null
												&& n2.toString().contains(
														"ParantezaDreapta")) {
											k = n3;
											return n3;
										} else {
											err = "Eroare. Asteptam o ')'!";
											return null;
										}
									} else {
										err = "Eroare. Asteptam o '('!";
										return null;
									}
								} else {
									err = "Eroare. Asteptam * sau / sau -!";
									return null;
								}
							} else {
								err = "Eroare. Asteptam o ')'!";
								return null;
							}
						} else {
							err = "Eroare. Asteptam o ')'!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o '('!";
						return null;
					}
				} else if (n1 != null
						&& (n1.toString().contains("Log")
								|| n1.toString().contains("Pow") || n1
								.toString().contains("Sqrt"))) {
					Nod n2 = identificare(sir);
					if (n2 != null && n2.toString().contains("Constanta")) {
						n = identificare(sir);
						if (n != null
								&& n.toString().contains("ParantezaStanga")) {
							n1.setFDrept(expression(sir));
							n = identificare(sir);
							if (n != null
									&& n.toString()
											.contains("ParantezaDreapta")) {
								n1.setFStang(n2);
								n2 = identificare(sir);
								if (n2 != null
										&& n2.toString().contains(
												"ParantezaDreapta")) {
									Nod n3 = identificare(sir);
									if (n3 != null
											&& (n3.toString()
													.contains("Produs")
													|| n3.toString().contains(
															"Cat") || n3
													.toString().contains(
															"Minus"))) {
										n = identificare(sir);
										if (n != null
												&& n.toString().contains(
														"ParantezaStanga")) {
											n3.setFStang(n1);
											n3.setFDrept(expression(sir));
											n = identificare(sir);
											if (n != null
													&& n.toString().contains(
															"ParantezaDreapta")) {
												k = n3;
												return n3;
											} else {
												err = "Eroare. Asteptam o ')'!";
												return null;
											}
										} else {
											err = "Eroare. Asteptam o '('!";
											return null;
										}
									} else {
										err = "Eroare. Asteptam * sau / sau -!";
										return null;
									}

								} else {
									err = "Eroare. Asteptam o ')'!";
									return null;
								}
							} else {
								err = "Eroare. Asteptam o ')'!";
								return null;
							}
						} else {
							err = "Eroare. Asteptam o ')'!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o constanta!";
						return null;
					}
				} else {
					err = "Eroare. Asteptam o functie cunoscuta!";
					return null;
				}

			} else 
			if (n != null
					&& (n.toString().contains("Log")
							|| n.toString().contains("Pow") || n.toString()
							.contains("Sqrt"))) {
				Nod n1 = identificare(sir);
				if (n1.toString().contains("Constanta")) {
					Nod n2 = identificare(sir);
					if (n2.toString().contains("ParantezaStanga")) {
						n.setFDrept(expression(sir));
						Nod n3 = identificare(sir);
						if (n3.toString().contains("ParantezaDreapta")) {
							n.setFStang(n1);
							k = n;
							return n;
						} else {
							err = "Eroare. Asteptam o ')'!";
							return null;
						}
					} else {
						err = "Eroare. Asteptam o '('!";
						return null;
					}
				} else {
					err = "Eroare. Asteptam o constanta!";
					return null;
				}
			}

			return expression(sir);
		}
	}

	public ArboreFunctional execute() {
		a = new ArboreFunctional(expression(sir));
		return a;
	}

	public ArboreFunctional unexecute() {
		return a;
	}

	public String getErr() {
		return this.err;
	}
}
